package com.followerback.resources;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import twitter4j.IDs;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.User;
import twitter4j.conf.ConfigurationBuilder;

import com.followerback.model.MatchedFollower;
import com.followerback.model.SearchPhrase;
import com.followerback.model.TwitterProfile;
import com.followerback.model.TwitterProfileChannel;
import com.followerback.model.TwitterProfileFollower;
import com.followerback.model.TwitterProfileTwitterProfileFollower;
import com.google.appengine.api.search.Index;
import com.google.appengine.api.search.IndexSpec;
import com.google.appengine.api.search.SearchServiceFactory;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
import com.google.appengine.api.taskqueue.TaskOptions.Method;
import com.google.appengine.api.utils.SystemProperty;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyService;

public class Resource {

	private static final String developmentModeURL = "http://localhost:8000";
	private static final String productionModeURL = "http://1.followerback.appspot.com/";
	
	public static Gson gson;
	public static TwitterFactory twitterFactory;
	public static String baseURL;
	
	static {
		
		baseURL = developmentModeURL;
		if(SystemProperty.environment.value() == SystemProperty.Environment.Value.Production)
			baseURL = productionModeURL;
		
		ObjectifyService.register(MatchedFollower.class);
		ObjectifyService.register(SearchPhrase.class);
		ObjectifyService.register(TwitterProfile.class);
		ObjectifyService.register(TwitterProfileChannel.class);
		ObjectifyService.register(TwitterProfileFollower.class);
		ObjectifyService.register(TwitterProfileTwitterProfileFollower.class);
		
		if(gson == null) {
	    	gson = new GsonBuilder().create();
        }
		
		ConfigurationBuilder cb = new ConfigurationBuilder();
		cb.setDebugEnabled(true)
		  .setOAuthConsumerKey("dQqHlgwmux4AVCS1svBACw")
		  .setOAuthConsumerSecret("KjW7FOHYzthUvcyzKcB7l12odbNfarVWtNT9rM0Yk0A");
		twitterFactory = new TwitterFactory(cb.build());
	}
	
	public static List<Long> getFollowerIDs(Twitter twitter, Long userID) {
		List<Long> followerIDs = new ArrayList<Long>();
		
		
		List<IDs> idsList = new ArrayList<IDs>();
		try {
			long cursor = -1;
			while(cursor != 0) {
				IDs ids;
				if(userID == null)
					ids = twitter.getFollowersIDs(cursor);
				else
					ids = twitter.getFollowersIDs(userID, cursor);
				idsList.add(ids);
				
				if(ids.hasNext())
					cursor = ids.getNextCursor();
				else
					cursor = 0;
			}
		} catch (TwitterException e) {}
		
		for(IDs ids : idsList) {
			for(long id : ids.getIDs())
				followerIDs.add(id);
		}
		
		return followerIDs;
	}
	
	public static List<Long> getFriendIDs(Twitter twitter, Long userID) {
		List<Long> friendIDs = new ArrayList<Long>();
		
		
		List<IDs> idsList = new ArrayList<IDs>();
		try {
			long cursor = -1;
			while(cursor != 0) {
				IDs ids;
				if(userID == null)
					ids = twitter.getFriendsIDs(cursor);
				else
					ids = twitter.getFriendsIDs(userID, cursor);
				idsList.add(ids);
				
				if(ids.hasNext())
					cursor = ids.getNextCursor();
				else
					cursor = 0;
			}
		} catch (TwitterException e) {}
		
		for(IDs ids : idsList) {
			for(long id : ids.getIDs())
				friendIDs.add(id);
		}
		
		return friendIDs;
	}
	
	public static Map<String,Object> getFollowerIDsByHandle(Twitter twitter, String handle, long cursor) 
			throws TwitterException {
		Map<String, Object> followerIDsCursorMap = new HashMap<String, Object>();
		List<Long> followerIDs = new ArrayList<Long>();
	
		
		// use cursor to get ids
		IDs ids = twitter.getFollowersIDs(handle, cursor);
		
		// save info
		for(long id : ids.getIDs())
			followerIDs.add(id);
		if(ids.hasNext())
			followerIDsCursorMap.put("cursor", ids.getNextCursor());
		
		followerIDsCursorMap.put("followerIDs", followerIDs);
		return followerIDsCursorMap;
	}
	
	protected Map<String,Long> getNextFollowerToBeProcessed(long userID, 
			Objectify objectify) {
		Map<String,Long> twitterProfileFollowerIDCursorMap = new HashMap<String, Long>();
		
		
		// get all users connections that haven't already been processed
		List<TwitterProfileTwitterProfileFollower> twitterProfileTwitterProfileFollowers = objectify
				.query(TwitterProfileTwitterProfileFollower.class).filter("twitterProfileID", userID)
				.filter("processed", false).order("cursorLastUpdated").list();
		
		// if list empty
		if(twitterProfileTwitterProfileFollowers.isEmpty()) {
			twitterProfileTwitterProfileFollowers = objectify
					.query(TwitterProfileTwitterProfileFollower.class).filter("twitterProfileID", userID)
					.order("cursorLastUpdated").list();
			for(TwitterProfileTwitterProfileFollower twitterProfileTwitterProfileFollower : 
				twitterProfileTwitterProfileFollowers) {
				// set all connections to not processed
				twitterProfileTwitterProfileFollower.setProcessed(true);
				
				// set all cursors to null
				twitterProfileTwitterProfileFollower.setCursor(-1);
			}
			
			objectify.put(twitterProfileTwitterProfileFollowers);
		}
		
		// get user with earliest access number
		TwitterProfileTwitterProfileFollower nextTwitterProfileTwitterProfileFollower = 
				twitterProfileTwitterProfileFollowers.get(0);
		twitterProfileFollowerIDCursorMap.put("twitterProfileFollowerID", 
				nextTwitterProfileTwitterProfileFollower.getTwitterProfileFollowerID());
		twitterProfileFollowerIDCursorMap.put("cursor", 
				nextTwitterProfileTwitterProfileFollower.getCursor());
		
		// return its cursor and twitter profile ID
		return twitterProfileFollowerIDCursorMap;
	}
	
	protected Index getTwitterProfileFollowerIndex() {
		IndexSpec indexSpec = IndexSpec.newBuilder().setName("brandFanzTwitterProfileFollowerIndex")
				.build();
	    return SearchServiceFactory.getSearchService().getIndex(indexSpec);
	}
	
	public static long[] objectArrayToPrimitive(List<Long> longList) {
		int longListSize = longList.size();
		long[] longArray = new long[longListSize];
		for(int longListIndex = 0; longListIndex < longListSize; longListIndex++) {
			longArray[longListIndex] = longList.get(longListIndex);
		}
		
		return longArray;
	}
	
	protected void postToIndexTwitterProfileIndex(long followerID) {
		Queue queue = QueueFactory.getDefaultQueue();
		
		TaskOptions taskOptions = TaskOptions.Builder.withUrl("/resources/follower/index/" 
				+followerID);
		
		queue.add(taskOptions);
	}
	
	protected void postToSaveFollowers(long twitterProfileID) {
		Queue queue = QueueFactory.getDefaultQueue();
		
		TaskOptions taskOptions = TaskOptions.Builder
				.withUrl("/resources/follower/save/" +twitterProfileID).method(Method.POST);
		
		queue.add(taskOptions);
	}
	
	protected void postToSaveFriends(long twitterProfileID) {
		Queue queue = QueueFactory.getDefaultQueue();
		
		TaskOptions taskOptions = TaskOptions.Builder
				.withUrl("/resources/friend/save/" +twitterProfileID).method(Method.POST);
		
		queue.add(taskOptions);
	}
	
	protected void postToSearchUsersFollowers(long userID, String token) {
		
		Queue queue = QueueFactory.getDefaultQueue();
		
		TaskOptions taskOptions = TaskOptions.Builder.withUrl("/resources/follower/search/followers/")
				.method(Method.POST).param("userID", ""+userID).param("token", token);
		
		queue.add(taskOptions);
	}
	
	protected void saveConnection(Objectify objectify, long followerID, Twitter twitter, 
			long twitterProfileID) throws TwitterException {
		Key<TwitterProfileFollower> twitterProfileFollowerKey = objectify
				.query(TwitterProfileFollower.class).filter("userID", followerID).getKey();
		
		// check to see if follower profile has been created
		long twitterProfileFollowerID;
		if(twitterProfileFollowerKey == null) {
			User user = twitter.showUser(followerID);
			TwitterProfileFollower twitterProfileFollower = new TwitterProfileFollower(
					user.getId(), user.getScreenName(), user.getBiggerProfileImageURL(), 
					user.getDescription());
			objectify.put(twitterProfileFollower);
			twitterProfileFollowerID = twitterProfileFollower.getId();
			
			if(!twitterProfileFollower.getDescription().isEmpty())
				postToIndexTwitterProfileIndex(twitterProfileFollower.getId());
		} else {
			twitterProfileFollowerID = twitterProfileFollowerKey.getId();
		}
		
		// check to see if there's a connection between this twitter profile and the follower
		if(objectify.query(TwitterProfileTwitterProfileFollower.class)
				.filter("twitterProfileID", twitterProfileID)
				.filter("twitterProfileFollowerID", twitterProfileFollowerID).count() == 0) {
			TwitterProfileTwitterProfileFollower twitterProfileTwitterProfileFollower = 
					new TwitterProfileTwitterProfileFollower(twitterProfileID, twitterProfileFollowerID);
			objectify.put(twitterProfileTwitterProfileFollower);
		}
	}
}
